package com.arashivision.onecamerademo;

import android.content.Context;
import android.net.Uri;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Surface;
import android.widget.SeekBar;
import android.widget.TextView;

import com.arashivision.arplayer.GlTarget;
import com.arashivision.insta360.arutils.source.SourceFactory;
import com.arashivision.insta360.sdk.render.controller.GestureController;
import com.arashivision.insta360.sdk.render.controller.gyro.GyroMatrixProvider;
import com.arashivision.insta360.sdk.render.controller.gyro.GyroMatrixType;
import com.arashivision.insta360.sdk.render.controller.gyro.VideoAntiShakeController;
import com.arashivision.insta360.sdk.render.player.IPlayerFactory;
import com.arashivision.insta360.sdk.render.player.PlayerCallback;
import com.arashivision.insta360.sdk.render.player.bgm.IBGMController;
import com.arashivision.insta360.sdk.render.renderer.Insta360PanoRenderer;
import com.arashivision.insta360.sdk.render.renderer.model.PlanarRenderModel;
import com.arashivision.insta360.sdk.render.renderer.model.SphericalRenderModel;
import com.arashivision.insta360.sdk.render.renderer.model.SphericalStitchModel;
import com.arashivision.insta360.sdk.render.renderer.strategy.FishEyeStrategy;
import com.arashivision.insta360.sdk.render.view.PanoramaView;

import org.rajawali3d.materials.textures.ISurfacePlayer;
import org.rajawali3d.math.Matrix4;
import org.rajawali3d.math.Quaternion;

import java.io.FileDescriptor;

//import com.arashivision.onestreamtarget.OneStreamTarget;

public class PreviewActivity extends AppCompatActivity {
    private static final String TAG = "OnePreviewActivity";
    private CameraService mCameraService;
    private PanoramaView mPreviewView;
    private Insta360PanoRenderer mRenderer;
    private Bundle mExtra = new Bundle();

    private Surface mSurface;
    private Surface mSurface2;

    private GlTarget mGlTarget;
    private GlTarget mGlTarget2;

    private boolean mDual = PlaneActivity.mDualStream;

    private SeekBar mDeltaBar;
    private TextView mDeltaValue;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_preview);

        mCameraService = CameraService.instance(PreviewActivity.this);
        //force old surface null
//        mCameraService.setSurface(null,null);
//        mCameraService.switchRenderMode(RenderMode.withGlRenderer(RenderMethod.PlanarKeep));
        mPreviewView = (PanoramaView) findViewById(R.id.apv_preview);
        mDeltaBar = findViewById(R.id.sb_delta);
        mDeltaValue = findViewById(R.id.sb_value);

        mDeltaValue.setHint("-500ms - 500ms");
        Log.d(TAG,"mDeltaBar " + mDeltaBar.isEnabled());
        mDeltaBar.setEnabled(true);

        mDeltaBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                if(!fromUser)
                    return;

                setDeltaProgress(progress);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });

        mDeltaBar.setProgress(500);
        setDeltaProgress(500);
        init();
    }

    private void setDeltaProgress(int progress)
    {
        Log.d(TAG,"progress " + progress);
        mDeltaValue.setText(Integer.toString(progress - 500));
        setPreviewDelta((progress - 500) * 1000000);
    }

    private void setPreviewDelta(long ns)
    {
        if(mCameraService != null)
        {
            mCameraService.setPreviewDeltaNs(ns);
        }
    }

    private void init() {
        String offset = PlaneActivity.mOffset;//"2_190_200_200_0.000_0.000_0.000_190_600_200_0_0_180_800_400_2323";//
        mPreviewView.setFrameRate(60.);
        mPreviewView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

        mRenderer = new Insta360PanoRenderer(getApplicationContext());

        mRenderer.initWithReducedMode(SourceFactory.create("usb://.insv", offset), new FishEyeStrategy(), new IPlayerFactory() {
            @Override
            public ISurfacePlayer makePlayer(PlayerCallback playerCallback) {
                return new CameraStream();
            }
        }, new SphericalStitchModel(mRenderer.getId()));

        //still has problem event not stich 180414
//        mRenderer.init(SourceFactory.create("usb://.insv"), new FishEyeStrategy(), new IPlayerFactory() {
//            @Override
//            public ISurfacePlayer makePlayer(PlayerCallback playerCallback) {
//                return new CameraStream();
//            }
//        }, new SphericalModel(mRenderer.getId()), new SingleScreen());

        mPreviewView.setRenderer(mRenderer);

        VideoAntiShakeController videoAntiShakeController = new VideoAntiShakeController(new GyroMatrixProvider() {
            @Override
            public float[] getMatrix(double v) {
//                Log.w(TAG, "use deprecated api: getCurrentGyroMatrix");
                return mCameraService.getCurrentGyroMatrix();
            }

            @Override
            public GyroMatrixType getGyroMatrixType() {
                return GyroMatrixType.ONE;
            }
        });

        GestureController controller = new GestureController(getApplicationContext(), mRenderer.getRenderModel().getCamera());
        controller.setEnabled(true);
        controller.setHolders(mRenderer.getRenderModel());
        mRenderer.getControllerManager().addController("gestureController", controller);

        setAntishakeEnabled(true, mRenderer, videoAntiShakeController, "usb://.insv");
    }

    private static Matrix4 getMatrix(float[] gyroMatrix){
        Log.i(TAG, "get matrix");
        Matrix4 matrix4 = new Matrix4(gyroMatrix);
        matrix4.transpose();
//        matrix4.dotMultiply(new Matrix4(new float[]{
//                1,1,-1,1,
//                1,1,-1,1,
//                -1,-1,1,1,
//                1,1,1,1,
//        }));
        return matrix4;
    }

    @Override
    protected void onDestroy() {
        mRenderer.onDestroy();
        mRenderer = null;
        super.onDestroy();
    }

    public static void setAntishakeEnabled(final boolean enable, final Insta360PanoRenderer renderer,
                                           final VideoAntiShakeController videoAntiShakeController, String url) {
        String lowerCaseUrl = url.toLowerCase();
        if (lowerCaseUrl.endsWith(".mp4") || lowerCaseUrl.endsWith(".insv")) {
            renderer.internalOfferTask(new Runnable() {
                @Override
                public void run() {
                    renderer.getRenderModel().buildModel(renderer, renderer.getSourceManager().getCurrentSource());
                    if (renderer.getRenderModel() instanceof SphericalRenderModel) {
                        Log.i("Insta360", "use vert transfer mode");
                        videoAntiShakeController.setHolders(renderer.getRenderModel().getLayerAt(1));
                    } else if (renderer.getRenderModel() instanceof PlanarRenderModel) {
                        videoAntiShakeController.setHolders(renderer.getRenderModel());
                    }
                    videoAntiShakeController.setEnabled(enable);
                    renderer.getControllerManager().addController(VideoAntiShakeController.class.getSimpleName(), videoAntiShakeController);
                    if (!enable) {
                        renderer.getRenderModel().getLayerAt(1).setOrientation(new Quaternion());
                    }
                }
            });
        } else {
            renderer.internalOfferTask(new Runnable() {
                @Override
                public void run() {
                    renderer.getControllerManager().removeController(VideoAntiShakeController.class.getSimpleName());
                    renderer.getRenderModel().getLayerAt(1).setOrientation(new Quaternion());
                }
            });
        }
    }

    class CameraStream implements ISurfacePlayer {
        @Override
        public boolean useGLTarget()
        {
            return PlaneActivity.mGLTarget;
        }

        @Override
        public boolean useDualStreamTarget()
        {
            return PlaneActivity.mDualStreamTarget;
        }

        @Override
        public boolean useStreamTarget()
        {
            return PlaneActivity.mStreamTarget;
        }

        @Override
        public boolean useStreamTargetShadowTexture()
        {
            return PlaneActivity.mStreamTargetShadowTexture;
        }

        @Override
        public boolean useDualStream()
        {
            return mDual;
        }

        @Override
        public void onCreateGLTarget(GlTarget glTarget)
        {
            Log.i(TAG, "camera stream, set glTarget: " + glTarget);
            mGlTarget = glTarget;
            if(mDual)
            {
                if(mGlTarget != null && mGlTarget2 != null)
                {
                    mCameraService.setSurface(mGlTarget,mGlTarget2);
                }
            }
            else
            {
                mCameraService.setSurface(mGlTarget);
            }
        }

        @Override
        public void onReleaseGLTarget(GlTarget glTarget)
        {
            if(mCameraService.getSurface() == glTarget)
            {
                if(mDual)
                {
                    mCameraService.setSurface(null);
                }
                else
                {
                    mCameraService.setSurface(null,null);
                }
            }
        }

        @Override
        public void onCreateSecGLTarget(GlTarget glTarget)
        {
            Log.i(TAG, "camera stream, set gltarget2: " + glTarget);
            mGlTarget2 = glTarget;
            if(mGlTarget != null && mGlTarget2 != null)
            {
                mCameraService.setSurface(mGlTarget,mGlTarget2);
            }
        }

        @Override
        public void onReleaseSecGLTarget(GlTarget glTarget)
        {
            if(mCameraService.getSurface2() == glTarget)
                mCameraService.setSurface(null,null);
        }

        @Override
        public void onCreateSurface(Surface surface) {
            Log.i(TAG, "camera stream, set surface: " + surface);
            mSurface = surface;
            if(mDual)
            {
                if(mSurface != null && mSurface2 != null)
                {
                    mCameraService.setSurface(mSurface,mSurface2);
                }
            }
            else
            {
                mCameraService.setSurface(mSurface);
            }
        }

        @Override
        public void onReleaseSurface(Surface surface) {
            if(mCameraService.getSurface() == surface)
            {
                mCameraService.setSurface(null);
            }
            else
            {
                Log.e(TAG,"releaseSurface mismtach");
            }
        }

        @Override
        public void onCreateSecSurface(Surface surface)
        {
            Log.i(TAG, "camera stream, set surface2: " + surface);
            mSurface2 = surface;
            if(mSurface != null && mSurface2 != null)
            {
                mCameraService.setSurface(mSurface,mSurface2);
            }
        }

        @Override
        public void onReleaseSecSurface(Surface surface)
        {
            if(mCameraService.getSurface2() == surface)
                mCameraService.setSurface(null,null);
            else
            {
                Log.e(TAG,"releaseSecSurface mismtach");
            }
        }

        @Override
        public void onCreateOneStreamTarget(Object target)
        {
            Log.d(TAG, "onCreateOneStreamTarget: " + target);
            mCameraService.setSurface(target);
        }

        @Override
        public void onReleaseOneStreamTarget(Object target)
        {
            Log.d(TAG, "onCreateOneStreamTarget: " + target);
            if(mCameraService.getSurface() == target)
                mCameraService.setSurface(null,null);
            else
            {
                Log.e(TAG,"onReleaseDualStreamTarget mismtach");
            }
        }

        @Override
        public void initPlayer() {
        }

        @Override
        public boolean isPlaying() {
            return true;
        }

        @Override
        public void destroy() {
        }

        @Override
        public void setDataSource(String s) throws Throwable {
        }

        @Override
        public void setDataSource(Context context, Uri uri) throws Throwable {
        }

        @Override
        public void setDataSource(FileDescriptor fileDescriptor) throws Throwable {
        }

        @Override
        public void setDataSource(FileDescriptor fileDescriptor, long l, long l1) throws Throwable {
        }

        @Override
        public void start() {
        }

        @Override
        public void stop() {
        }

        @Override
        public void setLooping(boolean b) {
        }

        @Override
        public void seekTo(int i) {
        }

        @Override
        public long getDuration() {
            return 0;
        }

        @Override
        public int getCurrentPosition() {
            return 0;
        }

        @Override
        public void pause() {
        }

        @Override
        public void resume() {
        }

        @Override
        public void setVolume(float v) {
        }

        @Override
        public float getVolume() {
            return 0;
        }

        @Override
        public String getGyro() {
            return null;
        }

        @Override
        public IBGMController getBGMController()
        {
            return null;
        }

        @Override
        public void setPlaybackSpeed(double speed)
        {

        }

        @Override
        public void setOnStateChangedListener(OnStateChangedListener onStateChangedListener) {
        }

        @Override
        public void setOnErrorListener(OnErrorListener onErrorListener) {
        }

        @Override
        public void setOnPreparedListener(OnPreparedListener onPreparedListener) {
        }

        @Override
        public void setOnSeekCompleteListener(OnSeekCompleteListener onSeekCompleteListener) {
        }

        @Override
        public void setOnCompletionListener(OnCompletionListener onCompletionListener) {
        }

        @Override
        public void setOnBufferingUpdateListener(OnBufferingUpdateListener onBufferingUpdateListener) {
        }

        @Override
        public void setOnRenderingFpsUpdateListener(OnRenderingFpsUpdateListener onRenderingFpsUpdateListener) {
        }

        @Override
        public void setOnRendererFpsReportListener(OnRendererFpsReportListener onRendererFpsReportListener)
        {

        }

        @Override
        public void setOption(String s, boolean b) {
        }

        @Override
        public void setOption(String s, int i) {
        }

        @Override
        public void setOption(String s, long l) {
        }

        @Override
        public void setOption(String s, double v) {
        }

        @Override
        public boolean readExtras()
        {
            return false;
        }

        @Override
        public Bundle getExtra()
        {
            return mExtra;
        }

        @Override
        public void setOnInfoListener(OnInfoListener onInfoListener) {
        }
    }
}
